import json
import google.protobuf.json_format as json_format

import coin.exchange.base.kr_rest.private_client_base as privcb
import coin.exchange.prex_futures.kr_rest.native_private_client as nprivc
from coin.exchange.prex_futures.kr_rest.currency import PrexCurrency
from coin.exchange.prex_futures.kr_rest.futures_product import PrexFuturesProduct
from coin.exchange.prex_futures.kr_rest.product_info import prex_product_info
from cc.appcoin2.support.order.py_parser import PyOrderParser
from coin2.exchange.order.system_pb2 import OrderSystemConfig
from coin2.exchange.symbology_pb2 import ProductConfig
from coin.proto.coin_query_pb2 import (
    AccountBalance,
    AccountPosition,
    CurrencyBalance,
    ProductPosition)


class PrexFuturesPrivateParser(object):
  @staticmethod
  def parse_balance(wallet_msg, margin_msg):
    balance_dict = {}
    assert 'wallet' in wallet_msg, wallet_msg
    for info in wallet_msg['wallet']:
      currency = PrexCurrency.FromStrNativeCurrency(info['currency'])
      total = float(info['walletBalance'])
      available = float(info['walletBalanceAvailable'])
      currency_str = currency.currency
      currency_balance = CurrencyBalance(
          currency=currency_str,
          available=available,
          total=total)
      assert currency_str not in balance_dict, currency_str
      balance_dict[currency_str] = currency_balance
    assert len(margin_msg['margin']) == 1, margin_msg
    margin_item = margin_msg['margin'][0]
    assert margin_item['currency'] == 'USD', margin_item
    balance_dict[margin_item['currency']].total += float(margin_item['unrealizedPnl'])
    each_balance = [balance_proto for balance_proto in balance_dict.values()]
    return AccountBalance(
        market_type='Futures', exchange='Prex', each_balance=each_balance)

  @staticmethod
  def parse_position(update_msg):
    position_list = []
    for info in update_msg['position']:
      product = PrexFuturesProduct.FromStrNativeProduct(info['symbol'])
      position_list.append(ProductPosition(
          symbol=product.symbol,
          net_position=float(info['position']),
          avg_entry_price=float(info['avgEntryPrice'])
      ))
    return AccountPosition(
        market_type='Futures', exchange='Prex', each_position=position_list)


class PrexFuturesPrivateClient(privcb.PrivateClientBase):
  ProductType = PrexFuturesProduct

  def __init__(self, key_file):
    privcb.PrivateClientBase.__init__(self)
    self.nprivc = nprivc.PrexFuturesNativePrivateClient(key_file=key_file)
    pi_bundle = prex_product_info._product_infos
    assert pi_bundle.HasField('mea')
    oss_config = OrderSystemConfig(
        mea=pi_bundle.mea,
        products=ProductConfig(norms=[pi.symbol for pi in pi_bundle.product_infos]))
    self._parser = PyOrderParser.from_mea_str(pi_bundle.mea)
    self._parser.add_product(oss_config.SerializeToString())

  def query_account_balance_impl(self):
    wallet_update = self.nprivc.query_wallet()
    margin_update = self.nprivc.query_margin()
    self._parser.parse_account_balance(json.dumps(wallet_update.msg))
    margin_update_msg = self._parser.parse_account_balance(json.dumps(margin_update.msg))
    account_balance = AccountBalance()
    json_format.Parse(margin_update_msg, account_balance)
    margin_update.msg = account_balance
    return margin_update

  def query_account_position_impl(self):
    update = self.nprivc.query_position()
    msg = self._parser.parse_account_position(json.dumps(update.msg))
    account_position = AccountPosition()
    json_format.Parse(msg, account_position)
    update.msg = account_position
    return update

  def query_cancel_product_impl(self, product):
    raise NotImplementedError

  def query_fills_impl(self, product):
    raise NotImplementedError

  def query_submit_impl(self, product, side, price, qty):
    raise NotImplementedError


if __name__ == "__main__":
  client = PrexFuturesPrivateClient(
      key_file='../../coin_key/view/xunke03/prex/view_key.json')
  print(client.query_account_balance_impl().msg)
  print(client.query_account_position_impl().msg)
